<?php

/*
 * 分页类
 */

class Page extends Base {
	
	//分页变量名称
	protected $page_name = 'p';
	
	//当前页码
	protected $current_page = 1;
	
	//记录总数
	protected $total_rows = 0;
	
	//每页显示记录数
	protected $per_page = 10;
	
	//基准路径
	protected $base_url = '/';
	
	//显示页码数
	protected $num_links = 10;

	//链接link_wrap标签，如li
	protected $link_wrap = '';
	
	/*
	 * 分页方式
	 * 1.在末尾增加/1
	 * 2.在末尾增加/p/1
	 * 3.传统的分页，?p=1
	 * 4.替换{p}为_1，一般用在生成静态列表时用
	 * 5.ajax分页，使用此模式需要自己在页面写出分页函数，例如function dopage(p, params){}
	 */
	protected $page_mode = 3;
	
	//ajax分页调用js函数名称
	protected $ajax_function = 'ajax_page';
	
	//上一页文字
	protected $prev_text = '上一页';
	
	//下一页文字
	protected $next_text = '下一页';
	
	//首页文字
	protected $first_text = '首页';
	
	//尾页文字
	protected $last_text = '尾页';

	//select形式的格式字符
	protected $select_format = '第%s页';
	
	//总共多少页
	protected $total_page = 0;
	
	protected $_valid = array(
		'page_name',
		'current_page',
		'total_rows',
		'per_page',
		'base_url',
		'num_links',
		'link_wrap',
		'page_mode',
		'prev_text',
		'next_text',
		'first_text',
		'last_text',
		'ajax_function',
		'select_format'
	);

	//分页偏移量array(开始, 结束)
	protected $_page_offset = array();

	public function __construct($config = array())
	{
		if ($config)
		{
			$this->config($config);
		}
	}
	
	/**
	 * 初始化
	 * @return boolean 总是返回TRUE
	 */
	public function init()
	{
		//计算总共页数
		$total_page = ceil($this->total_rows/$this->per_page);
		$this->total_page = $total_page ? $total_page : 1;
		
		//根据page_mode重新设置base_url，以适合不同的模式
		switch ($this->page_mode)
		{
			//1.在末尾增加/1
			case 1 :
				$this->base_url = rtrim($this->base_url, '/').'/';
				break;
			//2.在末尾增加/p/1
			case 2 :
				$this->base_url = rtrim($this->base_url, '/').'/'.$this->page_name.'/';
				break;
			//3.传统的分页，?p=1
			case 3 :
				$query = strstr($this->base_url, '?');
				parse_str(ltrim($query, '?'), $arr);
				if (isset($arr[$this->page_name]))
				{
					unset($arr[$this->page_name]);
				}
				$this->base_url = str_replace($query, '', $this->base_url).'?'.($arr ? (http_build_query($arr).'&'.$this->page_name.'='): ($this->page_name.'='));
				break;
			default :
				break;
		}

		$this->_page_offset = $this->page_offset($this->num_links);
		
		return TRUE;
	}
	
	/**
	 * 返回总页码数，最小值1
	 * @return integer 总页码数
	 */
	public function total()
	{
		return $this->total_page;
	}

	/**
	 * 返回总共多少条记录
	 * @return integer 总记录数
	 */
	public function rows()
	{
		return $this->total_rows;
	}

	/**
	 * 返回当前页码，最小值1
	 * @return integer 当前页码
	 */
	public function current()
	{
		return $this->current_page;
	}

	public function link_wrap(&$content, $link_wrap)
	{
		$link_wrap = isset($link_wrap) ? $link_wrap : $this->link_wrap;
		if ($link_wrap)
		{
			$content = str_replace(array('<a', '</a>'), array('<'.$link_wrap.'><a', '</a></'.$link_wrap.'>'), $content);
		}
	}

	/**
	 * 返回首页链接
	 * @param string $text 显示的文字
	 * @return string 首页链接
	 */
	public function first($text = '', $link_wrap = NULL)
	{
		$text = trim($text) ? trim($text) : $this->first_text;
		$first = '<a href="'.($this->current_page == 1 ? 'javascript:;' : $this->href(1)).'" class="first"/>'.$text.'</a>';
		$this->link_wrap($first, $link_wrap);
		return $first;
	}

	/**
	 * 返回上一页链接
	 * @param string $text 显示的文字
	 * @return string 上一页链接
	 */
	public function prev($text = '', $link_wrap = NULL)
	{
		$text = trim($text) ? trim($text) : $this->prev_text;
		$prev = ($this->current_page-1<1) ? ('<a href="javascript:;" class="prev">'.$text.'</a>') : ('<a href="'.$this->href($this->current_page-1).'" class="prev">'.$text.'</a>');
		$this->link_wrap($prev, $link_wrap);
		return $prev;
	}

	/**
	 * 返回下一页链接
	 * @param string $text 显示的文字
	 * @return string 下一页链接
	 */
	public function next($text = '', $link_wrap = NULL)
	{
		$text = trim($text) ? trim($text) : $this->next_text;
		$next = ($this->current_page+1>$this->total_page) ? ('<a href="javascript:;" class="next">'.$text.'</a>') : ('<a href="'.$this->href($this->current_page+1).'" class="next">'.$text.'</a>');
		$this->link_wrap($next, $link_wrap);
		return $next;
	}

	/**
	 * 返回最后页链接
	 * @param string $text 显示的文字
	 * @return string 最后页链接
	 */
	public function last($text = '', $link_wrap = NULL)
	{
		$text = trim($text) ? trim($text) : $this->last_text;
		$last = '<a href="'.($this->current_page>=$this->total_page ? 'javascript:;' : $this->href($this->total_page)).'" class="last"/>'.$text.'</a>';
		$this->link_wrap($last, $link_wrap);
		return $last;
	}

	/**
	 * 返回页码链接形式的分页
	 * @param boolean $more 是否显示more链接
	 * @return string 返回页码链接分页
	 */
	public function index($more = FALSE, $link_wrap = NULL)
	{
		$index = '';

		if ($more && ($this->current() >= $this->num_links))
		{
			$index .= '<a href="'.$this->href(1).'">1</a><a href="javascript:;" class="more">...</a>';
		}
		
		for ($i = $this->_page_offset[0]; $i <= $this->_page_offset[1]; $i++)
		{
			if ($this->current_page == $i)
			{
				$index .= '<a href="javascript:;" class="active">'.$i.'</a>';
			}
			else
			{
				$index .= '<a href="'.$this->href($i).'">'.$i.'</a>';
			}
		}

		if ($more && ($this->current() <= ($this->total() - $this->num_links)))
		{
			$index .= '<a href="javascript:;" class="more">...</a><a href="'.$this->href($this->total()).'">'.$this->total().'</a>';
		}

		$this->link_wrap($index, $link_wrap);
		return $index;
	}

	/**
	 * 返回select选择框样式的分页
	 * @param string $format 格式字符串
	 * @return string select选择框样式的分页
	 */
	public function select($format = '')
	{
		//随机的一个js函数名
		$fun = 'select_'.uniqid();
		$format = trim($format) ? trim($format) : $this->select_format;

		$select = '<script type="text/javascript">function '.$fun.'(p){'.$this->js_str().' return false;}</script><select onchange="'.$fun.'(this.value)">';
		
		for($i = $this->_page_offset[0]; $i <= $this->_page_offset[1]; $i++)
		{
			if($this->current_page == $i)
			{
				$select .= '<option value="'.$i.'" selected>'.sprintf($format, $i).'</option>';
			}
			else
			{
				$select .= '<option value="'.$i.'">'.sprintf($format, $i).'</option>';
			}
		}

		$select .= '</select>';

		return $select;
	}

	/**
	 * 返回文本库搜索页码
	 * @return string 搜索样式的分页
	 */
	public function search()
	{
		$uid = uniqid();
		//随机的js函数名
		$fun = 'go_'.$uid;
		//随机的分页属性名
		$page_id = 'p_'.$uid;
		
		$search = '<script type="text/javascript">function '.$fun.'(){var p = document.getElementById(\''.$page_id.'\').value;if ( ! /^[1-9][0-9]*$/.test(p)){return false;}else if(p>'.$this->total_page.'){p = '.$this->total_page.';} '.$this->js_str().' return false;}</script><form onsubmit="'.$fun.'(); return false;" style="display:inline"><input type="text name="'.$page_id.'" value="'.$this->current_page.'" id="'.$page_id.'" style="width:50px"/><input type="submit" value="GO" /></form>';
		return $search;
	}

	/**
	 * 返回js跳转的部分代码
	 * @return string 部分js代码
	 */
	protected function js_str()
	{
		$str = '';
		switch ($this->page_mode)
		{
			case 1:
			case 2:
			case 3:
				$str = "location.href = '".$this->base_url."'+p;";
				break;
			case 4:
				$str = "location.href = (p == 1) ? '".$this->base_url."'.replace('{p}', '') : '".$this->base_url."'.replace('{p}', '_' + p);";
				break;
			case 5:
				$str = $this->ajax_function.'(p);';
				break;
			default:
				break;
		}
		return $str;
	}

	/**
	 * 根据base_url和提供的参数$p返回一条完整的分页连接，这个方法一般是内部使用的
	 * @param  integer $p 页码
	 * @return string     一条完整的分页连接
	 */
	public function href($p = 1)
	{
		$url = '';
		switch ($this->page_mode)
		{
			case 1:
			case 2:
			case 3:
				$url = $this->base_url.$p;
				break;
			case 4:
				$url = ($p == 1) ? str_replace('{p}', '', $this->base_url) : str_ireplace('{p}', '_'.$p, $this->base_url);
				break;
			case 5:
				$url = "javascript:".$this->ajax_function."(".$p.");";
				break;
		}
		return $url;
	}

	/**
	 * 返回页码偏移，一个数组array(开始页, 最终页)
	 * @param integer $num 每页显示多少页
	 * @return array 返回一个数组array(开始页, 最终页)
	 */
	public function page_offset($num = 5)
	{
		$i = floor($num/2);
		
		if ($num%2 == 0)
		{
			$first = $this->current_page-$i+1;
			$last = $this->current_page+$i;
		}
		else
		{
			$first = $this->current_page-$i;
			$last = $this->current_page+$i;
		}

		if ($first < 1)
		{
			$last = ($last+1-$first)>$this->total_page ? $this->total_page : ($last+1-$first);
			$first = 1;
		}
		elseif ($last > $this->total_page)
		{
			$first = ($first-($last-$this->total_page))<1 ? 1 : ($first-($last-$this->total_page));
			$last = $this->total_page;
		}
		
		return array($first, $last);
	}

	public function set_current_page($current_page)
	{
		$this->current_page = intval($current_page) ? intval($current_page) : $this->current_page;
		return $this;
	}
	
	public function set_total_rows($total_rows)
	{
		$this->total_rows = intval($total_rows);
		return $this;
	}
	
	public function set_per_page($per_page)
	{
		$this->per_page = intval($per_page) ? intval($per_page) : $this->per_page;
		return $this;
	}

	public function set_num_links($num_links)
	{
		$this->num_links = intval($num_links);
		return $this;
	}

	public function set_page_mode($page_mode)
	{
		$this->page_mode = in_array(intval($page_mode), array(1, 2, 3, 4, 5)) ? intval($page_mode) : $this->page_mode;
		return $this;
	}

	public function set_ajax_function($ajax_function)
	{
		$this->ajax_function = ($ajax_function && is_string($ajax_function) && trim($ajax_function) != '') ? trim($ajax_function) : $this->ajax_function;
		return $this;
	}

	public function set_base_url($base_url)
	{
		$this->base_url = trim($base_url);
		return $this;
	}

	public function set_select_format($select_format)
	{
		if (trim($select_format))
		{
			$this->select_format = trim($select_format);
		}
		return $this;
	}

}